//
//  MyUserDefaults.swift
//  No-Storyboard-New-Project
//
//  Created by 黄中山 on 2019/9/27.
//  Copyright © 2019 potato. All rights reserved.
//

import Foundation

struct MyUserDefaults {
    
}


/// 普通属性用这个，不可空
@propertyWrapper
struct UserDefault<T> {
    let key: String
    let defaultValue: T
    var memoryValue: T?
    
    var wrappedValue: T {
        mutating get {
            if memoryValue != nil { return memoryValue! }
            memoryValue = UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
            return memoryValue!
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

/// 普通属性用这个，可空
@propertyWrapper
struct UserDefaultOptional<T> {
    let key: String
    let defaultValue: T?
    var memoryValue: T?
    
    var wrappedValue: T? {
        mutating get {
            if memoryValue != nil { return memoryValue }
            memoryValue = UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
            return memoryValue
        }
        set {
            switch newValue {
            case .some(let value):
                memoryValue = value
                UserDefaults.standard.set(value, forKey: key)
            case .none:
                memoryValue = nil
                UserDefaults.standard.removeObject(forKey: key)
            }
        }
    }
}

/// 自定义属性用这个，必须遵循Codable
@propertyWrapper
struct UserDefaultCustom<T: Codable> {

    struct Wrapper<T>: Codable where T: Codable {
        let wrapped: T
    }

    let key: String
    let defaultValue: T?
    var memoryValue: T?

    var wrappedValue: T? {
        mutating get {
            if memoryValue != nil { return memoryValue }
            
            guard let data = UserDefaults.standard.object(forKey: key) as? Data
                else { return defaultValue }
            
            do {
                let value = try JSONDecoder().decode(Wrapper<T>.self, from: data)
                memoryValue = value.wrapped
                return value.wrapped
            } catch {
                debugPrint(error.localizedDescription)
            }
            return nil
        }
        set {
            memoryValue = newValue
            if let value = newValue {
                do {
                    let data = try JSONEncoder().encode(Wrapper(wrapped:value))
                    UserDefaults.standard.set(data, forKey: key)
                } catch {
                    memoryValue = nil
                    debugPrint(error.localizedDescription)
                }
            } else {
                UserDefaults.standard.removeObject(forKey: key)
            }
        }
    }
}
